#define SCAN_NONE 0
#define SCAN_SCAN 1
#define SCAN_UPDATE 2

#define SCAN_UPDATEDELAY 1200
#define SCAN_SCANDELAY 1000
#define SCAN_SCANRANGE 750
#define SCAN_LOOTRANGE 60

#define SCAN_UPDATE_NONE 0
#define SCAN_UPDATE_REMOVE 1

objectdef ScanTarget
{
	variable string ID
	variable string Name
	variable int Priority 
	
	method Initialize(string ID, string Name, int Priority = 50)
	{
		This.ID:Set[${ID}]
		This.Name:Set[${Name}]
		This.Priority:Set[${Avatar.TargetPriority[${ID},${Priority}]}]
	}
}

objectdef ScanBlacklist
{
	variable string ID
	variable string Name
	variable int Expiration
	
	method Initialize(string ID, string Name, int Expiration = 0)
	{
		This.ID:Set[${ID}]
		This.Name:Set[${Name}]
		This.Expiration:Set[${Expiration}]
	}
}

objectdef Scanning inherits BotBase
{
	variable int LastScan = ${LavishScript.RunningTime}
	variable int LastUpdate = ${LavishScript.RunningTime}
	variable index:ScanTarget Targets
	variable index:ScanBlacklist Blacklist
	variable int TargetCount = 0
	variable uint NextTarget = 0

	method BlacklistID(string ID, int Expiration = 0)
	{
		This.Blacklist:Collapse
		if ${Expiration} == 0
		{
			;30 minutes
			Expiration:Set[${LavishScript.RunningTime} + 1800000]
		}

		if !${This.Blacklisted[${ID}]}
		{
			This.Blacklist:Insert[${ID},${Pawn[id,${ID}].Name},${Expiration}]
			This:UpdateBlacklist
		}
	}
	
	member Blacklisted(string ID)
	{
		variable int a = 1
		
		if ${This.Blacklist.Get[${a}](exists)}
		{
			do
			{
				if ${This.Blacklist.Get[${a}].ID.Equal[${ID}]} && (${LavishScript.RunningTime} < ${This.Blacklist.Get[${a}].Expiration} || ${This.Blacklist.Get[${a}].Expiration} == 1)
				{
					return TRUE
				}
			}
			while ${This.Blacklist.Get[${a:Inc}](exists)}
		}
		return FALSE
	}

	member GetBlacklisted(string ID)
	{
		variable int a = 1
		
		if ${This.Blacklist.Get[${a}](exists)}
		{
			do
			{
				if ${This.Blacklist.Get[${a}].ID.Equal[${ID}]} && (${LavishScript.RunningTime} < ${This.Blacklist.Get[${a}].Expiration} || ${This.Blacklist.Get[${a}].Expiration} == 1)
				{
					return ${a}
				}
			}
			while ${This.Blacklist.Get[${a:Inc}](exists)}
		}
		return ""
	}

	member GotLoot()
	{
		declare a uint local 0
		declare PAWNID uint local 0

		PAWNID:Set[${Pawn[Corpse, Radius, 5].ID}]
		if ${Pawn[id,${PAWNID}].Type.Equal[Corpse]}
		{
			if !${This.Blacklisted[${PAWNID}]}
			{
				return TRUE
			}
		}
		return FALSE
	}
	
	member FindLoot()
	{
		declare a uint local 0
		declare PAWNID uint local 0

		PAWNID:Set[${Pawn[Corpse, Radius, 5].ID}]
		if ${Pawn[id,${PAWNID}].Type.Equal[Corpse]}
		{
			if !${This.Blacklisted[${PAWNID}]}
			{
				return ${PAWNID}
			}
		}
		return ""
	}

	member FindTarget()
	{
		variable int TargetIndex = 1
		if ${This.TargetCount}
		{
			if ${Pawn[id,${This.Targets.Get[1].ID}].X} != 0 && ${Pawn[id,${This.Targets.Get[1].ID}].Y} != 0
			{
				return ${This.Targets.Get[1].ID}
			}
		}
		return ""
	}
	
	method ClearScanTarget()
	{
		if ${Targets.Get[1](exists)}
		{
			Targets:Remove[1]
			This:ClearTarget
		}
	}
	
	method Reset()
	{
		Targets:Collapse
		if ${Targets.Get[1](exists)}
		{
			do
			{
				Targets:Remove[1]
			}
			while ${Targets.Get[1](exists)}
		}
	}
	
	method Prioritize()
	{
		variable int a = 2
		variable int Total = 1
		
		This.Targets:Collapse
		Total:Set[${This.QueueCount}]
		
		if ${Total} > 1
		{
			do
			{
				if ${This.Targets.Get[${Math.Calc[${a} - 1]}].Priority} > ${This.Targets.Get[${Math.Calc[${a}]}].Priority}
				{
					This.Targets:Swap[${Math.Calc[${a} - 1]},${a}]
				}
			}
			while ${a:Inc} <= ${Total}
		}
		Event[TARGETS_UPDATED]:Execute
	}

	member QueueCount()
	{
		variable int a = 1
		
		if ${This.Targets.Get[${a}](exists)}
		{
			while ${This.Targets.Get[${Math.Calc[${a} + 1]}](exists)}
			{
				a:Inc
			}
			This.TargetCount:Set[${a}]
			return ${a}
		}
		This.TargetCount:Set[0]
		return 0
	}
	
	member InQueue(string ID)
	{
		variable int a = 1
		
		if ${This.Targets.Get[${a}](exists)}
		{
			do
			{
				if ${This.Targets.Get[${a}].ID.Equal[${ID}]}
				{
					return ${a}
				}
			}
			while ${This.Targets.Get[${a:Inc}](exists)}
		}
		return 0
	}

	method QueueTarget(string ID, int Priority = 50)
	{
		if ${This.InQueue[${ID}]} 
		{
			return
		}
		if ${Avatar.WantTarget[${ID}]} && !${This.Blacklisted[${ID}]} && !${Pawn[id,${ID}].Type.Equal[corpse]} 
		{
			This.Targets:Collapse
			This.TargetCount:Inc
			This.Targets:Insert[${ID},${Pawn[id,${ID}].Name},${Priority}]
			This:EA["Added target to queue: ${Pawn[id,${ID}].Name}"]
			This:Update
		}
	}

	member UpdateAction(int a)
	{
		variable string ID
		ID:Set[${This.Targets.Get[${a}].ID}]
		
		if !${Pawn[id,${ID}](exists)} || ${Pawn[id,${ID}].Type.Equal[corpse]} || ${Pawn[id,${ID}].Distance} > SCAN_SCANRANGE || (${Pawn[id,${ID}].X} == 0 && ${Pawn[id,${ID}].Y} == 0)
		{
			return SCAN_UPDATE_REMOVE
		}
		
		return SCAN_UPDATE_NONE
	}

	method Update()
	{
		variable int a = 1

		This.LastUpdate:Set[${LavishScript.RunningTime}]
		
		if ${This.Targets.Get[${a}](exists)}
		{
			do
			{
				switch ${This.UpdateAction[${a}]}
				{
					case SCAN_UPDATE_REMOVE
						This.Targets:Remove[${a}]
						break
					default
						;This.Targets.Get[${a}].Priority:Set[${Avatar.TargetPriority[${This.Targets.Get[${a}].ID},50]}]
						break
				}
			}
			while ${This.Targets.Get[${a:Inc}](exists)}
		}

		This:Prioritize
	}

	method UpdateBlacklist()
	{
		variable int a = 1
		variable string ID
		variable string ListItem
		UIElement[lstBlacklist@Blacklist@Pages@VG Wanderbot]:ClearItems
		if ${This.Blacklist.Get[${a}](exists)}
		{
			do
			{
				ID:Set[${This.Blacklist.Get[${a}].ID}]
				if (${LavishScript.RunningTime} < ${This.Blacklist.Get[${a}].Expiration} || ${This.Blacklist.Get[${a}].Expiration} == 1)
				{
					ListItem:Set["${Pawn[id,${ID}].Name} L${Pawn[id,${ID}].Level} ${Pawn[id,${ID}].Type}"]
					UIElement[lstBlacklist@Blacklist@Pages@VG Wanderbot]:AddItem[${ListItem},${ID},"ffaf0000"]
				}
			}
			while ${This.Blacklist.Get[${a:Inc}](exists)}
		}
	}

	method AddBlacklist()
	{
		variable int a = 1
		variable int Total
		variable string SItem
		Total:Set[${UIElement[lstTargets@Targets@Pages@VG Wanderbot].SelectedItems}]
		if ${Total}
		{
			do
			{
				SItem:Set[${UIElement[lstTargets@Targets@Pages@VG Wanderbot].SelectedItem[${a}].Value}]
				This:BlacklistID[${SItem}]
				This.Targets:Remove[${This.InQueue[${SItem}]}]
			}
			while ${a:Inc} <= ${Total}
		}
		This.Targets:Collapse
		This:Update
	}

	method RemoveBlacklist()
	{
		variable int a = 1
		variable int Total
		variable string SItem
		Total:Set[${UIElement[lstBlacklist@Blacklist@Pages@VG Wanderbot].SelectedItems}]
		if ${Total}
		{
			do
			{
				SItem:Set[${UIElement[lstBlacklist@Blacklist@Pages@VG Wanderbot].SelectedItem[${a}].Value}]
				This.Blacklist:Remove[${This.GetBlacklisted[${SItem}]}]
			}
			while ${a:Inc} <= ${Total}
		}
		This.Blacklist:Collapse
		This:UpdateBlacklist
	}

	method Scan()
	{
		variable int a = 0
		variable string PAWNID = 0
		variable int MinLevel = ${Math.Calc[${Me.Level}-5]}
		variable int MaxLevel = ${Math.Calc[${Me.Level}+2]}
		if ${MinLevel} < 1
		{
			MinLevel:Set[1]
		}

		This:UpdateBlacklist

		This.LastScan:Set[${LavishScript.RunningTime}]

		PAWNID:Set[${Pawn[Npc,levels,${MinLevel},${MaxLevel}].ID}]
		;This:EA["${PAWNID}, ${MinLevel}, ${MaxLevel}"]
		if ${Pawn[id,${PAWNID}].Type.Equal[NPC]}
		{
			if ${Pawn[id,${PAWNID}](exists)} && ${Pawn[id,${PAWNID}].ID}
			{
				This:QueueTarget[${PAWNID},50]
			}
		}
	}

	member NeedScan()
	{
		if ${Math.Calc[${LavishScript.RunningTime} - ${This.LastScan}]} > SCAN_SCANDELAY
		{
			return TRUE
		}
		return FALSE
	}
	
	member NeedUpdate()
	{
		if ${Math.Calc[${LavishScript.RunningTime} - ${This.LastUpdate}]} > SCAN_UPDATEDELAY && ${This.QueueCount}
		{
			return TRUE
		}
		return FALSE
	}

	member State()
	{	
		if ${This.NeedScan}
		{
			return SCAN_SCAN
		}

		if ${This.NeedUpdate}
		{
			return SCAN_UPDATE
		}
	
		return SCAN_NONE
	}
	
	method Pulse()
	{
		This.CurrentState:Set[${This.State}]
		switch ${This.CurrentState}
		{
			case SCAN_SCAN
				This:Scan
				break
			case SCAN_UPDATE
				This:Update
				break
			case SCAN_NONE
				break
		}
	}

	method Inject()
	{
		LavishScript:RegisterEvent[TARGETS_UPDATED]
		Event[S_CORE_EVENT_PULSE]:AttachAtom[${This.ObjectName}:Pulse]
	}
	 
	method Shutdown()
	{
		Event[S_CORE_EVENT_PULSE]:DetachAtom[${This.ObjectName}:Pulse]
		Event[TARGETS_UPDATED]:Unregister
	}
}